package com.cxs.service.impl;

import com.cxs.config.MinioProperties;
import com.cxs.service.BucketService;
import com.cxs.service.FileService;
import io.minio.GetObjectArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.RemoveObjectArgs;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

/**
 * @Author: cxs
 */
@Service
public class FileServiceImpl implements FileService {

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private BucketService bucketService;

    @Autowired
    private MinioProperties minioProperties;

    @Override
    public String uploadFile(String bucketName, MultipartFile file, String uniqueIdentifier) {
        String path = existFile(bucketName, uniqueIdentifier);
        if (StringUtils.hasText(path)) {
            return path;
        }
        String objectName = null;
        Boolean flag = bucketService.existBucket(bucketName); //获取桶名
        if (!flag) {
            bucketService.createBucket(bucketName);
        }
        try {
            String fileName = file.getOriginalFilename();
            objectName = new SimpleDateFormat("yyyy/MM/dd/").format(new Date())
                    + UUID.randomUUID().toString().replaceAll("-", "")
                    + fileName.substring(fileName.lastIndexOf("."));
            PutObjectArgs objectArgs = PutObjectArgs.builder()
                    .object(objectName)
                    .bucket(bucketName)
                    .contentType(file.getContentType())
                    .stream(file.getInputStream(), file.getSize(), -1)
                    .build();
            minioClient.putObject(objectArgs);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        // 存入redis或者mysql 为了后期秒传
        return minioProperties.getUrl() + "/" + bucketName + "/" + objectName;
    }

    /**
     * 判断文件是否存在，可以直接使用redis或者mysql做一个内容的md5加密
     * 然后进行判断
     *
     * @param bucketName
     * @param uniqueIdentifier 前端把文件的内容加密md5传入后端作为文件的唯一标识
     * @return
     */
    @Override
    public String existFile(String bucketName, String uniqueIdentifier) {
        // 查询数据库，这个uniqueIdentifier 如果有则直接返回存入的url
        return null;
    }

    @Override
    public void removeFile(String bucketName, String filePath) {
        try {
            minioClient.removeObject(
                    RemoveObjectArgs.builder().bucket(bucketName).object(filePath.replaceFirst("http://" + minioProperties.getUrl(), "")).build());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void downloadFile(String bucketName, String filePath, HttpServletResponse response) {
        String objectName = filePath.replaceFirst(minioProperties.getUrl() + "/" + bucketName + "/", "");
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            // 获取文件对象
            inputStream = minioClient.getObject(GetObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName).build());
            byte[] buf = new byte[1024];
            int length = 0;
            response.reset();
            response.setHeader("Content-Disposition", "attachment;filename=" +
                    URLEncoder.encode(objectName.substring(objectName.lastIndexOf("/") + 1), "UTF-8"));
            response.setContentType("application/octet-stream");
            response.setCharacterEncoding("UTF-8");
            // 输出文件
            while ((length = inputStream.read(buf)) > 0) {
                outputStream.write(buf, 0, length);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
